/**
 * Author: luoqi
 * Created Date: 2025-11-11 22:19:36
 * Last Modified: 2025-11-20 00:45:53
 * Modified By: luoqi at <**@****>
 * Copyright (c) 2025 <*****>
 * Description:
 */

#include <stdarg.h>
#include <usart.h>
#include <string.h>
#include <dma.h>
#include <tim.h>
#include "bsp.h"
#include "utils/ringbuf.h"
#include "utils/qmem.h"
#include "utils/printf.h"
#include "qtask/qtask.h"
#include "dbg/dbg.h"
#include "uart_port.h"
#include "tim_port.h"
#include "adc_port.h"
#include "cli.h"

#define LIST_ITERATOR(node, list)  \
    for (node = (list)->next; node != (list); node = node->next)

#define LIST_ITERATOR_SAFE(node, safe, list) \
    for (node = (list) ? (list)->next : NULL, safe = node ? node->next : NULL; \
         node && node != (list); \
         node = safe, safe = node ? node->next : NULL)

#define LIST_ENTRY(ptr, type, member)  \
   ((type *)((char *)(ptr) - ((size_t) &((type*)0)->member)))

static uint8_t membuf[2048] = { 0 };
static QMem mempool;

static QTaskSched task_sched;

static int cmd_ps_hdl(int argc, char *argv[])
{
    QTaskList *node = NULL;
    QTaskObj *task = NULL;
    kprintf(" %-10s %s %s %s\r\n", "Name", "Period", "Tick", "  Ready");
    LIST_ITERATOR(node, &task_sched.task_list) {
        task = LIST_ENTRY(node, QTaskObj, task_node);
        kprintf(" -%-10s %-6d %-6d %d\r\n", task->name, task->period, task->timer, task->isready);
    }
    return 0;
}

static int cmd_ktime(int argc, char **argv)
{
    uint64_t time = ktime();
    uint32_t s = time / 1000000;
    uint32_t ms = time / 1000 % 1000;
    uint32_t us = time % 1000;
    QSH("ktime: %lus%lums%luus [%lluus]\r\n", s, ms, us, time);
    return 0;
}

static int cmd_reboot(int argc, char **argv)
{
    HAL_NVIC_SystemReset();
    return 0;
}

__weak void task_immdiate_override(void)
{
    
}

int bsp_init(void)
{
    qmem_init(&mempool, membuf, sizeof(membuf), 4, 4, 0x55, NULL, NULL);
    qtask_sched_init(&task_sched);

    uart_port_init();
    cli_init();
    
    adc_start();

    tim_start(TIM_PORT_PWM1);
    tim_start(TIM_PORT_ENC2);
    tim_start(TIM_PORT_ENC3);
    tim_start(TIM_PORT_TIM4);

    cli_add("ps", cmd_ps_hdl, "Show task list");
    cli_add("ktime", cmd_ktime, "Show ktime");
    cli_add("reboot", cmd_reboot, "Reboot the system");
    dbg_init();

    qtask_sched_hook_set(&task_sched, task_immdiate_override);
    return 0;
}

void led_toggle(void)
{
    HAL_GPIO_TogglePin(BLINK_GPIO_Port, BLINK_Pin);
}

uint64_t ktime(void)
{
    TimVal val;
    tim_get(TIM_PORT_TIM4, &val);
    
    // return (uint64_t)val.count + val.overflow * 0xffff;
    return (uint64_t)val.count + val.overflow * __HAL_TIM_GET_AUTORELOAD(&htim4);
}

int kprintf(const char *fmt, ...)
{
    char buf[256] = { 0 };
    va_list args;
    va_start(args, fmt);
    int sz = vsnprintf(buf, sizeof(buf) - 1, fmt, args);
    va_end(args);

    if(sz < 0) {
        const char *err_str = " #! Print parse failed\r\n";
        sz = (int)strlen(err_str);
        memcpy(buf, err_str, sz);
    } else if(sz >= (int)sizeof(buf)) {
        sz = sizeof(buf) - 1;
    }

    return uart_write(UART_PORT1, buf, sz);
}

void task_tick_increase(void)
{
    qtask_tick_increase(&task_sched);
}

int task_add(const char *name, void (*handle)(void), size_t tick)
{
    QTaskObj *task = qmalloc(sizeof(QTaskObj));
    if(!task) {
        return -1;
    }
    int ret = qtask_add(&task_sched, task, name, handle, tick);
    if(ret != 0) {
        qfree(task);
        return ret;
    }
    return 0;
}

int task_suspend(const char *name)
{
    return qtask_suspend(&task_sched, name);
}

int task_resume(const char *name)
{
    return qtask_resume(&task_sched, name);
}

void *qmalloc(size_t sz)
{
    return qmem_alloc(&mempool, sz);
}

void qfree(void *ptr)
{
    qmem_free(&mempool, ptr);
}

void task_exec(void)
{
    qtask_exec(&task_sched);
}
